// Package utildownload contains internal helper functions related to file IO
// utilized by the primary mobsql app logic.
package utilfiles

import (
	"archive/zip"
	"crypto/sha256"
	"fmt"
	"git.sr.ht/~mil/mobsql/logger"
	"io"
	"io/ioutil"
	"os"
)

func FileChecksum(filepath string) string {
	return fmt.Sprintf(
		"C_%dM_%s",
		int(FileSizeMB(filepath)),
		fileSHA256Sum(filepath),
	)
}

func fileSHA256Sum(filepath string) string {
	sha := sha256.New()
	if csvFile, err := os.Open(filepath); err != nil {
		return fmt.Sprintf("Problem opening source file %s: %v", filepath, err)
	} else if _, err := io.Copy(sha, csvFile); err != nil {
		return fmt.Sprintf("Copy problem generating SHA256 sum from %s: %v", filepath, err)
	} else {
		return fmt.Sprintf("%x", sha.Sum(nil))
	}
}

func FileSizeMB(filepath string) float64 {
	if stat, err := os.Stat(filepath); err != nil {
		return 0
	} else {
		return float64(stat.Size()) / 1024 / 1024
	}
}

// TempDir creates a temporary directory in the platform-specific temporary
// directory - if that fails it uses the tmp subfolder in CacheDir
// (e.g. ~/.cache/mobroute/tmp).
//
// This is a workaround for certain platform that fail with the default
// TempDir such as Android which as of recent versions uses /data/local/tmp
// which is not writable
func TempDir(prefix string) (string, error) {
	if dir, err := ioutil.TempDir("", "mobroute_tempdir"); err == nil {
		return dir, nil
	} else if dir, err := ioutil.TempDir(CacheDir("tmp"), "mobroute_tempdir"); err != nil {
		return "", err
	} else {
		return dir, nil
	}
}

func UnzipZipArchive(validFiles []string, sourceZipPath, destPath string) error {
	if r, err := zip.OpenReader(sourceZipPath); err != nil {
		return err
	} else {
		defer r.Close()
		for _, f := range r.File {
			validFile := false
			for _, fileName := range validFiles {
				if fileName == f.Name {
					validFile = true
					break
				}
			}
			if !validFile {
				continue
			}

			// Open source file, create dest file, copy to dest, close source & dest
			if fileSource, err := f.Open(); err != nil {
				return err
			} else if fileDest, err := os.Create(destPath + "/" + f.Name); err != nil {
				return err
			} else if _, err := io.Copy(fileDest, fileSource); err != nil {
				return err
			} else {
				fileSource.Close()
				fileDest.Close()
			}
		}
	}
	return nil
}

func CacheDir(subFolder string) string {
	dir := os.Getenv("HOME") + "/.cache/mobroute" + "/" + subFolder
	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
		logger.Fatal(err)
	}
	return dir
}

func FileExists(filepath string) bool {
	if _, err := os.Stat(filepath); os.IsNotExist(err) {
		return false
	} else {
		return true
	}
}
